import React, { useEffect, useReducer } from 'react';

const context = React.createContext();
const MyProvider = context.Provider;

const Provider = props => {
  let initSate, reducers, effects, autorun;
  let store = props.store;

  if (Array.isArray(store)) {
    autorun = [];
    for (let i = 0; i < store.length; i++) {
      initSate = { ...initSate, ...store[i].state };
      reducers = { ...reducers, ...store[i].reducers };
      effects = { ...effects, ...store[i].effects };
      if (store[i].autorun) {
        autorun.push(store[i].autorun);
      }
    }
  } else {
    // store不是数组
    initSate = store.state != null ? store.state : {};
    reducers = store.reducers;
    effects = store.effects;
    if (store.autorun) {
      autorun = store.autorun;
    }
  }


  const reducer = (state, action) => {
    if (action.__loadingName == null) {
      return {...state, ...action};
    } else {
      let item = { ...state };
      item[action.__loadingName] = action.__loadingValue;
      return item;
    }
  };


  const [state, dispatch] = useReducer(reducer, initSate);

  const put = (action) => {
    let reducer = reducers[action.type];
    if (reducer != null) {
      let res = reducer(state, action.payload);
      dispatch(res);
    }
  };

  const call = async (action) => {
    let effect = effects[action.type];
    if (effect == null) {
      return;
    }
    if (action.loadingName != null) {
      dispatch({ __loadingName: action.loadingName, __loadingValue: true });
      await effect({ state, payload: action.payload }, { put, call });
      dispatch({ __loadingName: action.loadingName, __loadingValue: false });
    } else {
      await effect({ state, payload: action.payload }, { put, call });
    }
  };

  const proxyDispatch = async (action) => {
    await call(action);
  };

  const excuteAutorun = async () => {
    if (Array.isArray(autorun)) {
      for (let item of autorun) {
        await item({ state }, { put, call: proxyDispatch });
      }
    } else {
      await autorun({ state }, { put, call: proxyDispatch });
    }
  };

  useEffect(() => {
    excuteAutorun();
  }, [initSate]);
  return (
    <MyProvider value={{ state, dispatch: proxyDispatch }}>
      {props.children}
    </MyProvider>
  );

};

export { context, Provider };
